﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Drawing;
using System.Xml.Serialization;
using System.IO;
using System.IO.Compression;
using System.ComponentModel;
using System.Windows.Forms;
//using System.Data.SQLite;

namespace Maniac
{
    public class SecurityPriceEventArgs : EventArgs
    {
        public HistoricalPrice Price;
        public DateTime Date;
    }
    public class Security
    {
        public Security()
        {
            this.HistoricalPrices = new List<HistoricalPrice>();
            this.DayAggregates = new List<DayAggregate>();
            this.ivcColorTiers = new List<ColorTier>();
            this.ivsSecurityKeyDates = new List<SecurityKeyDate>();
            this.GainType = GainType.PriorClose;
            // by default, set the colortiers. If this object is 
            // persisted, it is the persisted object that will dictate
            // the color tiers.

            initializeColorTiers();
        }
        
        private void initializeColorTiers()
        {
            this.ivcColorTiers.Add(new ColorTier(46, -1, Color.Red));
            this.ivcColorTiers.Add(new ColorTier(56, 46, Color.Yellow));
            this.ivcColorTiers.Add(new ColorTier(101, 55, Color.GreenYellow));            
        }
        public FileInfo ItemsFile
        {
            get
            {
                return new FileInfo(Path.Combine(Application.StartupPath, ivsSymbol+".mnc"));
            }
        }
		public void LoadPrices(byte [] RawHistoricalData)
		{
			string textdata = System.Text.Encoding.UTF8.GetString(RawHistoricalData);

                string[] lines = textdata.Split(new char[] { '\n' });

                int tviLastYear = 0;
                int tviSessionID = -1;

                for (int i = 1; i < lines.Length; i++)
                {
                    if (lines[i].Length < 1)
                        continue;
                    string[] parts = lines[i].Split(new char[] { ',' });
                    string[] dateparts = parts[0].Split(new char[] { '-' });

                    HistoricalPrice tvHist = new HistoricalPrice();

                    tvHist.Year = Convert.ToInt32(dateparts[0]);
                    tvHist.Month = Convert.ToInt32(dateparts[1]);
                    tvHist.Day = Convert.ToInt32(dateparts[2]);

                    tvHist.Date = new DateTime(tvHist.Year, tvHist.Month, tvHist.Day);

                    HistoricalPrice tvhReturn = this.HistoricalPrices.Find(
                         delegate(HistoricalPrice tvhPrice)
                         {
                             return ((tvhPrice.Year == tvHist.Year) &&
                                 (tvhPrice.Month == tvHist.Month) &&
                                 (tvhPrice.Day == tvHist.Day));
                         }
                     );
                    if (tvhReturn != null)
                        continue;

                    tvHist.OpenPrice = Convert.ToDecimal(parts[1]);
                    tvHist.HighPrice = Convert.ToDecimal(parts[2]);
                    tvHist.LowPrice = Convert.ToDecimal(parts[3]);
                    tvHist.ClosePrice = Convert.ToDecimal(parts[4]);
                    tvHist.CloseAdjustedPrice = Convert.ToDecimal(parts[6]);
                    tvHist.Volume = Convert.ToInt64(parts[5]);
                    tvHist.Symbol = this.Symbol;

                    //trying to get the prior closing value
                    if (i < (lines.Length - 2))
                    {
                        string[] nextPart = lines[i + 1].Split(new char[] { ',' });

                        tvHist.PriorClosePrice = Convert.ToDecimal(nextPart[4]);
                    }
                    else
                    {
                        tvHist.PriorClosePrice = 0;
                    }

                    //is this a new year?
                    if (tviLastYear != tvHist.Year)
                    {
                        tviLastYear = tvHist.Year;
                        tviSessionID = -1;
                    }
                    tviSessionID++;

                    tvHist.Session = tviSessionID;
				
				foreach(SecurityKeyDate tvsDate in KeyDates)
				{
					if ((tvsDate.KeyDate.Date == tvHist.Date.Date) && (tvsDate.KeyDateType == SecurityKeyDateType.ExDividend))
					{
						tvHist.IsExDividendDate = true;						
					}
				}

                    this.HistoricalPrices.Add(tvHist);

                }
                this.HistoricalPrices.Sort(HistoricalPriceSorter.SortPricesByDateDescending);
		}
        public void persistLoad()
        {
            //need to reset the watchlist to be the recent items?
            if ((ItemsFile.Exists)&&(ItemsFile.Length>0))
            {
                //Decompress(ItemsFile);
                UncompressFile(ItemsFile.FullName);
                /*List<HistoricalPrice> tvsPrices = new List<HistoricalPrice>();

                XmlSerializer xml = new XmlSerializer(tvsPrices.GetType());
                */

				byte [] tvbPrices;
                using (Stream s = File.OpenRead(ItemsFile.FullName + ".tmp"))// ItemsFile.OpenRead())
                {
                    //tvsPrices = xml.Deserialize(s) as List<HistoricalPrice>;
					tvbPrices = new byte[s.Length];
					s.Read(tvbPrices, 0, tvbPrices.Length);
                    s.Close();
                    File.Delete(ItemsFile.FullName + ".tmp");
                }
               
                this.HistoricalPrices.Clear();
                /*foreach (HistoricalPrice tvhPrice in tvsPrices)
                {
                    if (!IsDateFound(tvhPrice))
                    {
                        this.HistoricalPrices.Add(tvhPrice);
                    }
                }*/
                /*this.HistoricalPrices = tvsPrices;*/
				LoadPrices(tvbPrices);
                //set the last download time here.
                this.LastDownloadTime = new DateTime(this.HistoricalPrices[0].Year, this.HistoricalPrices[0].Month, this.HistoricalPrices[0].Day);// ItemsFile.LastWriteTime;
                
			}
        }
		public void persistLoad2()
        {	
			DataTier.GetHistoricalPrices(this.HistoricalPrices, this.Symbol);
			//this.HistoricalPrices.Sort(HistoricalPriceSorter.SortPricesByDateDescending);
			if (this.HistoricalPrices.Count>0)
				this.LastDownloadTime = this.HistoricalPrices[0].Date;
        }
		private byte [] SavePrices()
		{
			string tvsPriceLine = "Date,Open,High,Low,Close,Volume,Adj Close\n";
			foreach(HistoricalPrice tvhPrice in HistoricalPrices)
			{
				tvsPriceLine += tvhPrice.Year + "-" + tvhPrice.Month + "-" + tvhPrice.Day + ","
					+ tvhPrice.OpenPrice + "," + tvhPrice.HighPrice + "," + tvhPrice.LowPrice + "," + tvhPrice.ClosePrice
						 + "," + tvhPrice.Volume + "," + tvhPrice.CloseAdjustedPrice + "\n";						
			}
			return System.Text.Encoding.UTF8.GetBytes(tvsPriceLine);
		}
        public void persistSave(byte [] SaveBytes)
        {   
            if (ItemsFile.Exists)
            {
                ItemsFile.Delete();
            }

            using (Stream s = ItemsFile.OpenWrite())
            {
                if (SaveBytes==null)
				    SaveBytes = SavePrices();
				s.Write(SaveBytes, 0, SaveBytes.Length);
            }
            CompressFile(ItemsFile.FullName);
        }
		
		public void persistSave2(byte [] SaveBytes)
        {	
			// TODO: Only insert new records
			// TODO: Either on insert, OR after, calculate the dayaggregates.
			
			
			
			int tviSymbolID = DataTier.GetSymbolID(this.Symbol);
			
			//this is the byte array from the web.
			//it needs to go into the DB.
			string history = System.Text.Encoding.UTF8.GetString(SaveBytes);
			
            // trim off unused characters from end of line
            history = history.Replace("\r", "");
            // split to array on end of line
            string[] rows = history.Split('\n');
           
			DateTime dtNow1 = DateTime.Now;
			DataTier.SaveRawHistoricalData(rows, tviSymbolID);
			DataTier.ETLDayAggregates(this.Symbol);
			//DataTier.ETLDayAggregateHistoricalPrice(this.Symbol);
			Console.WriteLine(DateTime.Now-dtNow1);
			
			 
        }
        public static void Compress(FileInfo fi)
        {
            // Get the stream of the source file.
            using (FileStream inFile = fi.OpenRead())
            {
                // Prevent compressing hidden and 
                // already compressed files.
                if ((File.GetAttributes(fi.FullName)
                    & FileAttributes.Hidden)
                    != FileAttributes.Hidden & fi.Extension != ".mnc")
                {
                    // Create the compressed file.
                    using (FileStream outFile =
                                File.Create(fi.FullName + ".mnc"))
                    {
                        using (GZipStream Compress =
                            new GZipStream(outFile,
                            CompressionMode.Compress))
                        {
                            // Copy the source file into 
                            // the compression stream.
                            byte [] buffer = new byte[inFile.Length];
                            inFile.Read(buffer, 0, buffer.Length);
                            Compress.Write(buffer,0,buffer.Length);                            
                        }
                    }
                }
            }
        }

        public static void Decompress(FileInfo fi)
        {
            // Get the stream of the source file.
            using (FileStream inFile = fi.OpenRead())
            {
                // Get original file extension, for example
                // "doc" from report.doc.gz.
                string curFile = fi.FullName;
                string origName = curFile.Remove(curFile.Length -
                        fi.Extension.Length);

                //Create the decompressed file.
                using (FileStream outFile = File.Create(origName))
                {
                    using (GZipStream Decompress = new GZipStream(inFile,
                            CompressionMode.Decompress))
                    {
                        // Copy the decompression stream 
                        // into the output file.
                        byte[] buffer = new byte[4096];
                        int n = Decompress.Read(buffer, 0, buffer.Length);
                        outFile.Write(buffer, 0, n);
                        //Decompress.CopyTo(outFile);

                    }
                }
            }            
        }

        public static void CompressFile(string path)
        {
            string tvsOriginalFilename = path;
            string tvsTemporaryFileName = tvsOriginalFilename + ".tmp";

            File.Move(tvsOriginalFilename, tvsTemporaryFileName);
            FileStream sourceFile = File.OpenRead(tvsTemporaryFileName);
            FileStream destinationFile = File.Create(tvsOriginalFilename);

            byte[] buffer = new byte[sourceFile.Length];
            sourceFile.Read(buffer, 0, buffer.Length);

            using (GZipStream output = new GZipStream(destinationFile,
                CompressionMode.Compress))
            {                

                output.Write(buffer, 0, buffer.Length);
            }

            // Close the files.
            sourceFile.Close();
            destinationFile.Close();

            File.Delete(tvsTemporaryFileName);
        }

        public static void UncompressFile(string path)
        {
            string tvsOriginalFilename = path;
            string tvsTemporaryFileName = tvsOriginalFilename + ".tmp";

            FileStream sourceFile = File.OpenRead(tvsOriginalFilename);
            FileStream destinationFile = File.Create(tvsTemporaryFileName);

            // Because the uncompressed size of the file is unknown, 
            // we are using an arbitrary buffer size.
            byte[] buffer = new byte[4096];
            int n;

            using (GZipStream input = new GZipStream(sourceFile,
                CompressionMode.Decompress, false))
            {
                do
                {
                    n = input.Read(buffer, 0, buffer.Length);
                    destinationFile.Write(buffer, 0, n);
                } while (n > 0);
            }

            // Close the files.
            sourceFile.Close();
            destinationFile.Close();

            
        }

		private DayType ivdDayType;
        public DayType SecurityDayType
        {
            get
            {
                return ivdDayType;
            }
            set
            {
                ivdDayType = value;
            }
        }
		
        private string ivsSymbol;
        public string Symbol
        {
            get
            {
                return ivsSymbol;
            }
            set
            {
                ivsSymbol = value.ToUpper();
            }
        }

        private List<HistoricalPrice> ivlHistoricalPrices;
        
        public List<HistoricalPrice> HistoricalPrices
        {
            get
            {
                return ivlHistoricalPrices;
            }
            set
            {
                ivlHistoricalPrices = value;
            }
        }
        private Image iviLogoImage=null;
        public Image LogoImage
        {
            get
            {
                if (iviLogoImage != null)
                    return iviLogoImage;
                else
                {
                    //attempt to load from resources
                    iviLogoImage = (Image)Properties.Resources.ResourceManager.GetObject(ivsSymbol);
                    return iviLogoImage;
                }
            }
           
        }

        public DateTime[] EarningsDates
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }

        public DateTime[] ExDividendDates
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }

        private List<DayAggregate> ivlDayAggregates;
        public List<DayAggregate> DayAggregates
        {
            get
            {
                return ivlDayAggregates;
            }
            set
            {
                ivlDayAggregates = value;
            }
        }
/*
        public FundamentalIndicators Fundamental
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }
*/
        private int iviNumSame=0;
        public int NumSame
        {
            get
            {
                return iviNumSame;
            }
        }
        private int iviNumTotal = 0;
        public int NumTotal
        {
            get
            {
                return iviNumTotal;
            }
        }
        public void Calculate(DateTime fvsStart, DateTime fvsEnd)
        {
			switch (SecurityDayType)
			{
			case (DayType.Calendar):
			{
				calculateCalendar(fvsStart, fvsEnd);
				break;
			}
			case DayType.Incremental:
			{
				calculateIncremental();
				break;
			}
			case DayType.Fuzzy:
			{
				calculateFuzzy();
				break;
			}
			}
		}
		private void calculateFuzzy()
		{
		}
		private void calculateIncremental()
		{
			//imho, this is the method which will yield the most accurate results.
			//each year, trading starts on session #1, then continues thru session #N.
			//these sessions occur as they fall on dates. In one year, they may be 
			//a friday, the next a monday.
			foreach (HistoricalPrice tvhPrice in HistoricalPrices)
            {
				DayAggregate tvdAggregateToModify = null;
				
				//if the year is the current year, 
				
				if (tvhPrice.Session>(DayAggregates.Count-1))
				{
					tvdAggregateToModify = new DayAggregate();
					if (tvhPrice.Year == DateTime.Now.Year)
					{
                    tvdAggregateToModify.Month = tvhPrice.Month;
                    tvdAggregateToModify.Day = tvhPrice.Day;
					}
                    tvdAggregateToModify.Symbol = this.Symbol;
                    tvdAggregateToModify.HistoricalPrices.Add(tvhPrice);
                    DayAggregates.Add(tvdAggregateToModify);
				}
				else
					tvdAggregateToModify = DayAggregates[tvhPrice.Session];
				
				//fillAggregate(tvdAggregateToModify, tvhPrice,0);
			}
		}
        public virtual event EventHandler ProcessingHistoricalPrice;

        protected virtual void OnProcessingHistoricalPrice(SecurityPriceEventArgs e)
        {
            if (ProcessingHistoricalPrice != null)
                ProcessingHistoricalPrice(this, e);
        }
		private void calculateCalendar(DateTime fvsStart, DateTime fvsEnd)
		{
			this.DayAggregates.Clear();
			DataTier.GetDayAggregates(this.DayAggregates, this.Symbol);
		}
		public void CalculateAccuracy()
		{
			iviNumSame=0;
            iviNumTotal = 0;
			foreach (DayAggregate tvDay in DayAggregates)
			{
                if (!DateTime.IsLeapYear(DateTime.Now.Year) && tvDay.Month == 2 && tvDay.Day == 29)
                    continue;
                DateTime tvdTemp = new DateTime(DateTime.Now.Year, tvDay.Month, tvDay.Day);
                if ((tvdTemp.DayOfWeek == DayOfWeek.Saturday) || (tvdTemp.DayOfWeek == DayOfWeek.Sunday))
                    continue;
				if ((tvDay.RiseProbability<50)&&(tvDay.MostRecentActualGain<0))
					iviNumSame++;
                else if ((tvDay.RiseProbability > 50) && (tvDay.MostRecentActualGain > 0))
					iviNumSame++;
                else if ((tvDay.RiseProbability == 50) && (tvDay.MostRecentActualGain == 0))
					iviNumSame++;
                iviNumTotal++;
			}
		}
        public PriceDataDownloader PriceDownloader
        {
            get
            {
                return ivoPriceDataDownloader;
            }
            set
            {
                ivoPriceDataDownloader = value;
            }
        }
        public DateDataDownloader DateDownloader
        {
            get
            {
                return ivoDateDataDownloader;
            }
            set
            {
                ivoDateDataDownloader = value;
            }
        }
		private int iviOrdinalPosition;
        public int OrdinalPosition
        {
            get
            {
                return iviOrdinalPosition;
            }
            set
            {
                iviOrdinalPosition = value;
            }
        }

        private PriceDataDownloader ivoPriceDataDownloader;
        private DateDataDownloader ivoDateDataDownloader;
        

        private List<ColorTier> ivcColorTiers;
        public List<ColorTier> ColorTiers
        {
            get
            {
                return ivcColorTiers;
            }
            set
            {
                ivcColorTiers = value;
            }
        }
        private GainType ivgGainType;
        public GainType GainType
        {
            get
            {
                return ivgGainType;
            }
            set
            {
                ivgGainType = value;
            }
        }
        private DateTime ivdLastDownload = new DateTime(1950,1,1);
        public DateTime LastDownloadTime
        {
            get
            {
                return ivdLastDownload;
            }
            set
            {
                ivdLastDownload = value;
            }
        }

        private List<Maniac.SecurityKeyDate> ivsSecurityKeyDates;

        public System.Collections.Generic.List<Maniac.SecurityKeyDate> KeyDates
        {
            get
            {
                return ivsSecurityKeyDates;
            }
            set
            {
                ivsSecurityKeyDates = value;
            }
        }
    }
}

